﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace PickGold.Api
{
	/// <summary>
	/// kernel32.dll
	/// </summary>
	public static class Kernel32
	{
		/// <summary>
		/// kernel32.dll
		/// </summary>
		public const string DLL = Common.DLL_KERNEL32;

		/// <summary/>
		[DllImport(DLL)]
		public static extern void GetWindowsDirectory(StringBuilder WinDir, int count);

		/// <summary/>
		[DllImport(DLL)]
		public static extern void GetSystemDirectory(StringBuilder SysDir, int count);

		/// <summary/>
		[DllImport(DLL)]
		public static extern void GetSystemInfo(ref CPU_INFO cpuinfo);

		/// <summary/>
		[DllImport(DLL)]
		public static extern void GetSystemTime(ref SYSTEMTIME_INFO stinfo);

		/// <summary/>
		[DllImport(DLL)]
		public static extern long WritePrivateProfileString(string section, string key, string value, string file);
		/// <summary/>
		[DllImport(DLL)]
		public static extern long GetPrivateProfileString(string section, string key, string def, StringBuilder result, int size, string file);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hWnd"></param>
		/// <param name="nCmdShow"></param>
		/// <returns></returns>
		[DllImport(DLL)]
		public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

		/// <summary>
		/// 打开控制台窗口
		/// </summary>
		[DllImport(DLL)]
		public static extern bool AllocConsole();
		/// <summary>
		/// 释放控制台窗口
		/// </summary>
		[DllImport(DLL)]
		public static extern bool FreeConsole();

		/// <summary>
		/// 获取控制台窗口
		/// </summary>
		[DllImport(DLL)]
		public static extern IntPtr GetConsoleWindow();
		/// <summary>
		/// 获取控制台窗口标题
		/// </summary>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern int GetConsoleTitle(StringBuilder sb, int capacity);
		/// <summary>
		/// 设置控制台窗口标题
		/// </summary>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool SetConsoleTitle(string title);
		/// <summary/>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int mode);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GetStdHandle(int nStdHandle);
		/// <summary/>
		[DllImport(DLL)]
		public static extern bool Beep(int freq, int dur);
		/// <summary/>
		[DllImport(DLL)]
		public static extern int GetLastError();

		/// <summary>
		/// 加载指定的动态连接库
		/// </summary>
		[DllImport(DLL)]
		public extern static IntPtr LoadLibrary(string lpLibFileName);
		/// <summary>
		/// 
		/// </summary>
		/// <param name="lpLibFileName">A string that specifies the file name of the module to load. This name is not related to the name stored in a library module itself, as specified by the LIBRARY keyword in the module-definition (.def) file.</param>
		/// <param name="hFile">This parameter is reserved for future use. It must be NULL.</param>
		/// <param name="dwFlags">
		/// DONT_RESOLVE_DLL_REFERENCES = 0x00000001;
		/// LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010;
		/// LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
		/// LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040;
		/// LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
		/// LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200;
		/// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;
		/// LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100;
		/// LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800;
		/// LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400;
		/// LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
		/// </param>
		/// <returns></returns>
		[DllImport(DLL)]
		public extern static IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, int dwFlags);
		/// <summary/>
		[DllImport(DLL)]
		public static extern int VirtualAllocEx(IntPtr hwnd, int lpaddress, int size, int type, int tect);
		/// <summary/>
		[DllImport(DLL)]
		public static extern int WriteProcessMemory(IntPtr hwnd, int baseaddress, string buffer, int nsize, int filewriten);
		/// <summary>
		/// 获取指定动态连接库中的函数句柄
		/// </summary>
		[DllImport(DLL)]
		public static extern IntPtr GetProcAddress(IntPtr hwnd, string lpname);
		/// <summary/>
		[DllImport(DLL)]
		public extern static IntPtr FreeLibrary(IntPtr lib);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GetModuleHandleA(string name);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr CreateRemoteThread(IntPtr hwnd, int attrib, int size, IntPtr address, int par, int flags, IntPtr threadid);
		/// <summary>
		/// Adds a directory to the search path used to locate DLLs for the application
		/// </summary>
		[DllImport(DLL)]
		public static extern IntPtr SetDllDirectory(string lpPathName);

		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GlobalAlloc(int wFlags, int dwBytes);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GlobalLock(int hMem);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GlobalUnlock(int hMem);
		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr GlobalFree(int hMem);
		/// <summary/>
		[DllImport(DLL)]
		public static extern void GlobalMemoryStatus(ref MEMORY_INFO meminfo);

		/// <summary/>
		[DllImport(DLL, SetLastError = true)]
		public static extern long FileTimeToSystemTime([In, Out] ref FILETIME_INFO FileTime, [In, Out] ref SYSTEMTIME_INFO SystemTime);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool GetFileInformationByHandle(IntPtr hFile, [In, Out] ref BY_HANDLE_FILE_INFORMATION lpFileInformation);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern int GetFileSize(IntPtr hFile, ref int lpFileSizeHigh);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool GetFileSizeEx(IntPtr hFile, ref long lpFileSize);//, ref LARGE_INTEGER lpFileSize);LARGE_INTEGER{ int LowPart; int HighPart; }

		/// <summary>
		/// 创建我们要操作驱动的映射文件
		/// </summary>
		[DllImport(DLL, SetLastError = true)]
		public static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)] string strName, uint nAccess, uint nShareMode, IntPtr lpSecurity, uint nCreationFlags, uint nAttributes, IntPtr lpTemplate);

		/// <summary/>
		[DllImport(DLL, SetLastError = true)]
		public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hDevice"></param>
		/// <param name="dwIoControlCode"></param>
		/// <param name="InBuffer">REPARSE_DATA_BUFFER</param>
		/// <param name="nInBufferSize"></param>
		/// <param name="OutBuffer">REPARSE_DATA_BUFFER</param>
		/// <param name="nOutBufferSize"></param>
		/// <param name="pBytesReturned"></param>
		/// <param name="lpOverlapped"></param>
		/// <returns></returns>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool DeviceIoControl(IntPtr hDevice, [MarshalAs( UnmanagedType.U4)] uint dwIoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned, IntPtr lpOverlapped);
		
		/// <summary>
		/// 创建符号连接
		/// </summary>
		/// <param name="lpSymlinkFileName">符号文件名</param>
		/// <param name="lpTargetFileName">目标文件名</param>
		/// <param name="dwFlags">SYMLINK_FLAG_DIRECTORY = 1</param>
		/// <returns>是否成功</returns>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern IntPtr FindFirstFile(string fileName, [In, Out] ref WIN32_FIND_DATA findFileData);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool FindNextFile(IntPtr findFile, [In, Out] ref WIN32_FIND_DATA findFileData);

		/// <summary/>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool FindClose(IntPtr hFindFile);

		/// <summary>
		/// 创建硬连接
		/// </summary>
		/// <param name="lpFileName">新文件名</param>
		/// <param name="lpExistingFileName">相同分区中已存在的文件名</param>
		/// <param name="mustBeNull">空</param>
		/// <returns>是否成功</returns>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr mustBeNull);

		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);

		/// <summary>
		/// This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
		/// </summary>
		/// <param name="lpFileName">
		/// The name of the file.
		/// The string must consist of characters from the 8-bit Windows character set. The OpenFile function does not support Unicode file names or opening named pipes.
		/// </param>
		/// <param name="lpReOpenBuff">
		/// A pointer to the OFSTRUCT structure that receives information about a file when it is first opened.
		/// The structure can be used in subsequent calls to the OpenFile function to see an open file.
		/// The OFSTRUCT structure contains a path string member with a length that is limited to OFS_MAXPATHNAME characters, which is 128 characters. Because of this, you cannot use the OpenFile function to open a file with a path length that exceeds 128 characters. The CreateFile function does not have this path length limitation.
		/// </param>
		/// <param name="wStyle">
		/// The action to be taken.
		/// </param>
		/// <returns>
		/// If the function succeeds, the return value specifies a file handle to use when performing file I/O. To close the file, call the CloseHandle function using this handle.
		/// If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.
		/// </returns>
		[DllImport(DLL)]
		public static extern IntPtr OpenFile(string lpFileName, ref OFSTRUCT lpReOpenBuff, OF wStyle);

		/// <summary/>
		[DllImport(DLL)]
		public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

		/// <summary/>
		[DllImport(DLL)]
		public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, IntPtr lpOverlapped);
		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, OVERLAPPED lpOverlapped);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, OVERLAPPED lpOverlapped);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool GetCommState(IntPtr nCid, ref DCB lpDCB);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool SetCommState(IntPtr nCid, ref DCB lpDCB);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool GetCommTimeouts(IntPtr hFile, ref COMMTIMEOUTS lpCommTimeouts);

		/// <summary/>
		[DllImport(DLL, SetLastError = true, CharSet = CharSet.Auto)]
		public static extern bool SetCommTimeouts(IntPtr hFile, ref  COMMTIMEOUTS lpCommTimeouts);

		/// <summary/>
		[DllImport(DLL, SetLastError = true)]
		public static extern bool CloseHandle(IntPtr handle);

		/// <summary/>
		public static BY_HANDLE_FILE_INFORMATION GetFileInformation(string file)
		{
			var h = CreateFile(file, FILE_ACCESS.GENERIC_NONE,
				FILE_SHARE.READ | FILE_SHARE.WRITE | FILE_SHARE.DELETE,
				IntPtr.Zero, CREATION_DISPOSITION.OPEN_EXISTING,
				FILE_ATTRIBUTE.BACKUP_SEMANTICS | FILE_ATTRIBUTE.OPEN_REPARSE_POINT, IntPtr.Zero);
			var s = new BY_HANDLE_FILE_INFORMATION();
			var b = Kernel32.GetFileInformationByHandle(h, ref s);
			var i = Kernel32.GetLastError();
			Kernel32.CloseHandle(h);
			if (b || i == 0)
				return s;

			throw i.GetException();
		}
		/// <summary/>
		public static BY_HANDLE_FILE_INFORMATION GetFileInformation(IntPtr file)
		{
			var s = new BY_HANDLE_FILE_INFORMATION();
			if (GetFileInformationByHandle(file, ref s))
				return s;

			throw ERROR.GetException();
		}

		/// <summary/>
		public static bool CreateJunctionLink(string junctionPoint, string targetDir, bool overwrite)
		{
			targetDir = Path.GetFullPath(targetDir);

			if (!Directory.Exists(targetDir))
				throw new IOException("Target path does not exist or is not a directory.");

			if (Directory.Exists(junctionPoint))
			{
				if (!overwrite)
					throw new IOException("Directory already exists and overwrite parameter is false.");
			}
			else
			{
				Directory.CreateDirectory(junctionPoint);
			}

			var h = CreateFile(junctionPoint, FILE_ACCESS.GENERIC_WRITE,
				FILE_SHARE.READ | FILE_SHARE.WRITE | FILE_SHARE.DELETE,
				IntPtr.Zero, CREATION_DISPOSITION.OPEN_EXISTING,
				FILE_ATTRIBUTE.BACKUP_SEMANTICS | FILE_ATTRIBUTE.OPEN_REPARSE_POINT, IntPtr.Zero);
			if (h == IntPtr.Zero)
				throw ERROR.GetException();

			var rdb = new REPARSE_DATA_BUFFER(IntPtr.Zero);
			rdb.SubstituteName = targetDir;
			var bytesReturned = 0;
			var result = rdb.DeviceIoControl(h, FSCTL.SET_REPARSE_POINT, out bytesReturned);
			var error = Marshal.GetLastWin32Error();
			CloseHandle(h);
			if (!result)
				throw error.GetException();

			return result;
		}

		/// <summary/>
		public static string TargetJunctionLink(string junctionPoint)
		{
			if (!Directory.Exists(junctionPoint) && !File.Exists(junctionPoint))
				throw new IOException("Target path does not exist or is not a directory.");

			var h = CreateFile(junctionPoint, FILE_ACCESS.GENERIC_NONE,
				FILE_SHARE.READ | FILE_SHARE.WRITE | FILE_SHARE.DELETE,
				IntPtr.Zero, CREATION_DISPOSITION.OPEN_EXISTING,
				FILE_ATTRIBUTE.BACKUP_SEMANTICS | FILE_ATTRIBUTE.OPEN_REPARSE_POINT, IntPtr.Zero);
			if (h == IntPtr.Zero)
				throw Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());

			var rdb = new REPARSE_DATA_BUFFER(IntPtr.Zero);
			var bytesReturned = 0;
			var result = rdb.DeviceIoControl(h, FSCTL.GET_REPARSE_POINT, out bytesReturned);
			var error = Marshal.GetLastWin32Error();
			CloseHandle(h);
			if (!result)
			{
				if (error == ERROR.NOT_A_REPARSE_POINT)
					return null;

				throw error.GetException();
			}

			if (rdb.ReparseTag == ReparseTagType.Symlink)
				return rdb.PrintName;

			return rdb.SubstituteName;
		}

		/// <summary/>
		public static bool DeleteJunctionLink(string junctionPoint)
		{
			if (!Directory.Exists(junctionPoint))
				throw new IOException("Target path does not exist or is not a directory.");

			var h = CreateFile(junctionPoint, FILE_ACCESS.GENERIC_WRITE,
				FILE_SHARE.READ | FILE_SHARE.WRITE | FILE_SHARE.DELETE,
				IntPtr.Zero, CREATION_DISPOSITION.OPEN_EXISTING,
				FILE_ATTRIBUTE.BACKUP_SEMANTICS | FILE_ATTRIBUTE.OPEN_REPARSE_POINT, IntPtr.Zero);
			if (h == IntPtr.Zero)
				throw Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());

			var rdb = new REPARSE_DATA_BUFFER(IntPtr.Zero);
			var bytesReturned = 0;
			var result = rdb.DeviceIoControl(h, FSCTL.DELETE_REPARSE_POINT, out bytesReturned);
			var error = Marshal.GetLastWin32Error();
			CloseHandle(h);
			if (!result)
				throw error.GetException();

			if (Directory.Exists(junctionPoint))
				Directory.Delete(junctionPoint);
			else if (File.Exists(junctionPoint))
				File.Delete(junctionPoint);
			return result;
		}

		/// <summary>
		/// DLL注入
		/// </summary>
		/// <param name="dllFile">dll file</param>
		/// <param name="processName">process name</param>
		private static void DllLoad(string dllFile, string processName)
		{
			int writeProcessMemory;
			int virtualAllocEx;
			IntPtr loadLibraryA;
			IntPtr createRemoteThread;
			int dlllength = dllFile.Length + 1;
			Process[] ps = Process.GetProcesses();//取得所有进程 
			foreach (Process p in ps) //遍历进程 
			{
				if (p.ProcessName.IndexOf(processName, StringComparison.OrdinalIgnoreCase) < 0)
					continue;

				//下面开始注入 
				virtualAllocEx = VirtualAllocEx(p.Handle, 0, dlllength, 4096, 4);//申请内存空间 
				if (virtualAllocEx == 0) //返回0则操作失败，下面都是 
					throw new Exception("申请内存空间失败！！");

				writeProcessMemory = WriteProcessMemory(p.Handle, virtualAllocEx, dllFile, dlllength, 0); //写内存 
				if (writeProcessMemory == 0)
					throw new Exception("写内存失败！！");

				loadLibraryA = GetProcAddress(GetModuleHandleA("Kernel32"), "LoadLibraryA"); //取得loadlibarary在kernek32.dll地址 
				if (loadLibraryA == IntPtr.Zero)
					throw new Exception("无法取得函数的入口点！！");

				createRemoteThread = CreateRemoteThread(p.Handle, 0, 0, loadLibraryA, virtualAllocEx, 0, IntPtr.Zero); //创建远程线程。 
				if (createRemoteThread == IntPtr.Zero)
					throw new Exception("创建远程线程失败！！");

				//已成功注入dll!!;
			}
			throw new Exception("没有发现指定的进程！！");
		}

		/// <summary/>
		public enum STD_HANDLE
		{
			/// <summary>
			/// STD_INPUT_HANDLE
			/// </summary>
			INPUT = -10,
			/// <summary>
			/// STD_OUTPUT_HANDLE
			/// </summary>
			OUTPUT = -11,
			/// <summary>
			/// STD_ERROR_HANDLE
			/// </summary>
			ERROR = -12
		}
	}
}
